#include "Builders.h"
#include "BuilderUtils.h"

String file_ext = "";
String dc = "ldmd2";
void   GccBuilder::AddFlags ( Index<String>& cfg )
{
}

//Выводит имя компилятора (c++ по умолчанию)
String GccBuilder::CompilerName() const
{
	if ( !IsNull ( compiler ) )
		return compiler;

	return "c++";
}

//Должна объединить команды Си и команды Ди
String GccBuilder::CmdLine ( const String& package, const Package& pkg )
{
	String cc = CompilerName();
	cc << " -c ";

for ( String s : pkg_config )
		cc << " `pkg-config --cflags " << s << "`";

	cc << ' ' << IncludesDefinesTargetTime ( package, pkg );

	dc << " --linker=ld.lld --gcc=" << CompilerName() << "-c ";//для ldmd2


	return cc;
}

//Преобразует бинарный файл в объектный
void GccBuilder::BinaryToObject ( String objfile, CParser& binscript, String basedir,
		const String& package, const Package& pkg )
{
	String fo = BrcToC ( binscript, basedir );
	String tmpfile = ForceExt ( objfile, ".c" );
	SaveFile ( tmpfile, fo );
	String cc = CmdLine ( package, pkg );
	cc << " -c -o " << GetPathQ ( objfile ) << " -x c " << GetPathQ ( tmpfile );
	int slot = AllocSlot();

	if ( slot < 0 || !Run ( cc, slot, objfile, 1 ) )
		throw Exc ( Format ( "Ошибка при компиляции бинарного объекта '%s'.", objfile ) );
}

//Строит пакет
bool GccBuilder::BuildPackage ( const String& package, Vector<String>& linkfile, Vector<String>& immfile,
		String& linkoptions, const Vector<String>& all_uses, const Vector<String>& all_libraries,
		int opt )
{
	if ( HasFlag ( "MAKE_MLIB" ) && !HasFlag ( "MAIN" ) )
		return true;

	if ( HasFlag ( "OSX" ) && HasFlag ( "GUI" ) )
	{
		String folder;
		String name = GetFileName ( target );

		if ( GetFileExt ( target ) == ".app" )
			target = target + "/Contents/MacOS/" + GetFileTitle ( target );
		else
			target = target + ".app/Contents/MacOS/" + GetFileName ( target );

		RealizePath ( target );
	}

	SaveBuildInfo ( package );

	int i;
	String packagepath = PackagePath ( package );
	Package pkg;
	pkg.Load ( packagepath );
	String packagedir = GetFileFolder ( packagepath );
	ChDir ( packagedir );
	PutVerbose ( "cd " + packagedir );
	IdeConsoleBeginGroup ( package );
	Vector<String> obj;

	bool is_shared = HasFlag ( "SO" );
	String shared_ext = ( HasFlag ( "WIN32" ) ? ".dll" : ".so" );

	Vector<String> sfile, isfile;
	Vector<String> soptions, isoptions;
	bool           error = false;

	String pch_header;

	Index<String> nopch, noblitz;

	bool blitz = HasFlag ( "BLITZ" );
	bool release = !HasFlag ( "DEBUG" );
	bool objectivec = HasFlag ( "OBJC" );

	if ( HasFlag ( "OSX" ) )
		objectivec = true;

	for ( i = 0; i < pkg.GetCount(); i++ )
	{
		if ( !IdeIsBuilding() )
			return false;

		if ( !pkg[i].separator )
		{
			String gop = Gather ( pkg[i].option, config.GetKeys() );
			Vector<String> srcfile = CustomStep ( pkg[i], package, error );

			if ( srcfile.GetCount() == 0 )
				error = true;

			for ( int j = 0; j < srcfile.GetCount(); j++ )
			{
				String fn = NormalizePath ( srcfile[j] );
				String ext = GetSrcType ( fn );
				file_ext = ext;

				if ( ext != ".d" )
				{
					if ( findarg ( ext, ".c", ".cpp", ".cc", ".cxx", ".brc", ".s", ".ss" ) >= 0 ||
						 objectivec && findarg ( ext, ".mm", ".m" ) >= 0 ||
						 ( !release && blitz && ext == ".icpp" ) ||
						 ext == ".rc" && HasFlag ( "WIN32" ) )
					{
						if ( FindIndex ( sfile, fn ) < 0 )
						{
							sfile.Add ( fn );
							soptions.Add ( gop );
						}
					}

					else
						if ( ext == ".icpp" )
						{
							isfile.Add ( fn );
							isoptions.Add ( gop );

						}

						else
							if ( ext == ".o" )
								obj.Add ( fn );
							else
								if ( ext == ".a" || ext == ".so" )
									linkfile.Add ( fn );
								else
									if ( IsHeaderExt ( ext ) && pkg[i].pch && allow_pch && !blitz )
									{
										if ( pch_header.GetCount() )
											PutConsole ( GetFileName ( fn ) + ": несколько PCH не допускается. Проверьте файл конфигурации." );
										else
											pch_header = fn;
									}

					if ( pkg[i].nopch )
					{
						nopch.Add ( fn );

						if ( allow_pch && release )
							noblitz.Add ( fn );
					}

					if ( pkg[i].noblitz )
						noblitz.Add ( fn );

					if ( ext == ".c" )
					{
						nopch.Add ( fn );
					}
				}

				else
					nopch.Add ( fn );

			}
		}
	}

	String cc = CmdLine ( package, pkg );

     cc << " -mthreads";

	if ( ( HasFlag ( "DEBUG_MINIMAL" ) || HasFlag ( "DEBUG_FULL" ) ) && file_ext != ".d" )
	{
		cc << ( HasFlag ( "WIN32" ) && HasFlag ( "CLANG" ) ? " -gcodeview -fno-limit-debug-info" : " -ggdb" );
		cc << ( HasFlag ( "DEBUG_FULL" ) ? " -g2" : " -g1" );
	}

    //ДИНИМАЧЕСКАЯ БИБЛИОТЕКА
	String fuse_cxa_atexit;

	if ( is_shared && file_ext == ".d" )
	{
		//для ldmd2
		dc << " -shared";
	}

	else//для clang/gcc
	{
		cc << " -shared -fPIC";
		fuse_cxa_atexit = " -fuse-cxa-atexit";
	}

    //СТАТИЧЕСКАЯ БИБЛИОТЕКА
	if ( !HasFlag ( "SHARED" ) && !is_shared && file_ext != ".d" ) //для clang/gcc
	{
		cc << " -static ";
		cc << ' ' << Gather ( pkg.option, config.GetKeys() );
		cc << " -fexceptions";
	}

	else //для ldmd2
		dc << " -lib";

#if 0
	if ( HasFlag ( "OSX" ) && file_ext != ".d" )
	{
		if ( HasFlag ( "POWERPC" ) && file_ext != ".d" )
			cc << " -arch ppc";

		if ( HasFlag ( "X86" && file_ext != ".d" ) )
			cc << " -arch i386";
	}

#endif

	if ( file_ext != ".d" ) //для clang/gcc
	{
		if ( !release )
			cc << " -D_DEBUG " << debug_options;
		else
			cc << ' ' << release_options;
	}

	else //для ldmd2
	{
		if ( !release )
			dc << " -debug " << debug_options;
		else
			dc << ' ' << release_options;
	}

	if ( pkg.nowarnings && file_ext != ".d" )
		cc << " -w";

	int recompile = 0;

	Blitz b;

	if ( blitz )
	{
		BlitzBuilderComponent bc ( this );
		b = bc.MakeBlitzStep ( sfile, soptions, obj, immfile, ".o", noblitz, package );
		recompile = b.build;
	}

	for ( i = 0; i < sfile.GetCount(); i++ )
	{
		String fn = sfile[i];
		String ext = ToLower ( GetFileExt ( fn ) );

		if ( findarg ( ext, ".rc", ".brc", ".c", ".d" ) < 0 && HdependFileTime ( sfile[i] ) > GetFileTime ( CatAnyPath ( outdir, GetFileTitle ( fn ) + ".o" ) ) )
			recompile++;
	}

	String pch_use;

	String pch_file;

	if ( file_ext != ".d" )
	{

		if ( recompile > 2 && pch_header.GetCount() )
		{
			String pch_header2 = CatAnyPath ( outdir, GetFileTitle ( pch_header ) + "$pch.h" );
			pch_file = pch_header2 + ".gch";
			SaveFile ( pch_header2, "#include <" + pch_header + ">" ); // CLANG needs a copy of header

			int pch_slot = AllocSlot();
			StringBuffer sb;

			sb << Join ( cc, cpp_options ) << " -x c++-header " << GetPathQ ( pch_header ) << " -o " << GetPathQ ( pch_file );

			PutConsole ( "Прекомпилирование заголовка: " + GetFileName ( pch_header ) );

			if ( pch_slot < 0 || !Run ( ~sb, pch_slot, pch_file, 1 ) )
				error = true;

			Wait();

			pch_use = " -I" + GetPathQ ( outdir ) + " -include " + GetFileName ( pch_header2 ) + " -Winvalid-pch ";
		}
	}

	if ( blitz && b.build )
	{
		PutConsole ( "БЛИЦ:" + b.info );
		int slot = AllocSlot();

		if ( file_ext != ".d" && slot < 0 || !Run ( String().Cat() << Join ( cc, cpp_options ) << ' '
				<< GetPathQ ( b.path )
				<< " -o " << GetPathQ ( b.object ), slot, b.object, b.count ) )
			error = true;

		else
			if ( file_ext == ".d" && slot < 0 || !Run ( String().Cat() << dc << ' '
					<< GetPathQ ( b.path )
					<< " -of" << GetPathQ ( b.object ), slot, b.object, b.count ) )
				error = true;
	}

	int first_ifile = sfile.GetCount();

	sfile.AppendPick ( pick ( isfile ) );
	soptions.AppendPick ( pick ( isoptions ) );

	int ccount = 0;

	for ( i = 0; i < sfile.GetCount(); i++ )
	{
		if ( !IdeIsBuilding() )
			return false;

		String fn = sfile[i];

		String ext = ToLower ( GetFileExt ( fn ) );

		bool rc = ( ext == ".rc" );

		bool brc = ( ext == ".brc" );

		bool init = ( i >= first_ifile );

		String objfile = CatAnyPath ( outdir, SourceToObjName ( package, fn ) ) + ( rc ? "$rc.o" : brc ? "$brc.o" : ".o" );

		if ( GetFileName ( fn ) == "Info.plist" )
			Info_plist = LoadFile ( fn );

		if ( HdependFileTime ( fn ) > GetFileTime ( objfile ) )
		{
			PutConsole ( GetFileName ( fn ) );
			int time = msecs();
			bool execerr = false;

			if ( rc )
			{
				String exec;
				String windres = "windres";
				int q = compiler.ReverseFind ( '-' ); // clang32 windres name is i686-w64-mingw32-windres.exe

				if ( q > 0 )
					windres = compiler.Mid ( 0, q + 1 ) + windres;

				exec << FindInDirs ( host->GetExecutablesDirs(), windres ) << " -i " << GetPathQ ( fn );

				if ( cc.Find ( " -m32 " ) >= 0 )
					exec << " --target=pe-i386 ";

				exec << " -o " << GetPathQ ( objfile ) << Includes ( " --include-dir=", package, pkg )
				<< DefinesTargetTime ( " -D", package, pkg ) + ( HasFlag ( "DEBUG" ) ? " -D_DEBUG" : "" );

				PutVerbose ( exec );

				int slot = AllocSlot();

				execerr = ( slot < 0 || !Run ( exec, slot, objfile, 1 ) );
			}

			else
				if ( brc )
				{
					try
					{
						String brcdata = LoadFile ( fn );

						if ( brcdata.IsVoid() )
							throw Exc ( Format ( "ошибка при чтении файла '%s'", fn ) );

						CParser parser ( brcdata, fn );

						BinaryToObject ( objfile, parser, GetFileDirectory ( fn ), package, pkg );
					}

					catch ( Exc e )
					{
						PutConsole ( e );
						execerr = true;
					}
				}

				else
				{
					String exec = cc;

					if ( ext == ".c" )
						exec << Join ( " -x c", c_options ) << ' ';
					else
						if ( ext == ".s" || ext == ".S" )
							exec << " -x assembler-with-cpp ";
						else
							if ( ext == ".m" )
								exec << fuse_cxa_atexit << " -x objective-c ";
							else
								if ( ext == ".mm" )
									exec << fuse_cxa_atexit << Join ( " -x objective-c++ ", cpp_options ) << ' ';
								else
									if ( ext != ".d" ) //для ldmd2
									{
										exec << fuse_cxa_atexit << Join ( " -x c++", cpp_options ) << ' ';
										exec << pch_use;
										exec << GetPathQ ( fn )  << " " << soptions[i] << " -o " << GetPathQ ( objfile );
									}

									else
									{

										dc << GetPathQ ( fn )  << " " << " -of" << GetPathQ ( objfile );
									}

					PutVerbose ( exec );

					int slot = AllocSlot();
					execerr = ( slot < 0 || !Run ( exec, slot, objfile, 1 ) );
				}

			if ( execerr )
				DeleteFile ( objfile );

			error |= execerr;

			PutVerbose ( "скомпилировано за " + GetPrintTime ( time ) );

			ccount++;
		}

		immfile.Add ( objfile );

		if ( init )
			linkfile.Add ( objfile );
		else
			obj.Add ( objfile );
	}

	if ( error )
	{
		IdeConsoleEndGroup();
		return false;
	}

	MergeWith ( linkoptions, " ", Gather ( pkg.link, config.GetKeys() ) );

	if ( linkoptions.GetCount() )
		linkoptions << ' ';

	bool making_lib = HasFlag ( "MAKE_LIB" ) || HasFlag ( "MAKE_MLIB" );

	if ( !making_lib )
	{
		Vector<String> libs = Split ( Gather ( pkg.library, config.GetKeys() ), ' ' );
		linkfile.Append ( libs );
	}

	if ( pch_file.GetCount() )
		OnFinish ( callback1 ( DeletePCHFile, pch_file ) );

	if ( !HasFlag ( "MAIN" ) )
	{
		if ( HasFlag ( "BLITZ" ) && !HasFlag ( "SO" ) || HasFlag ( "NOLIB" ) || making_lib )
		{
			linkfile.Append ( obj ); // Simply link everything as .o files...
			IdeConsoleEndGroup();
			return true;
		}

		IdeConsoleEndGroup();

		if ( !Wait() )
			return false;

		String product;

		if ( is_shared )
			product = GetSharedLibPath ( package );
		else
			product = CatAnyPath ( outdir, GetAnyFileName ( package ) + ".a" );

		String hproduct = product;

		Time producttime = GetFileTime ( hproduct );

		if ( obj.GetCount() )
		{
			linkfile.Add ( product );
			immfile.Add ( product );
		}

		for ( int i = 0; i < obj.GetCount(); i++ )
			if ( GetFileTime ( obj[i] ) > producttime )
				return CreateLib ( product, obj, all_uses, all_libraries, Gather ( pkg.link, config.GetKeys() ) );

		return true;
	}

	IdeConsoleEndGroup();

	obj.Append ( linkfile );
	linkfile = pick ( obj );
	return true;
}

//Создаёт библиотеку
bool GccBuilder::CreateLib ( const String& product, const Vector<String>& obj,
		const Vector<String>& all_uses, const Vector<String>& all_libraries,
		const String& link_options )
{
	int libtime = msecs();
	String hproduct = product;
	String lib;
	bool is_shared = HasFlag ( "SO") || HasFlag ( "SHARED");

	if ( is_shared )
	{
		lib = CompilerName();
		lib << " -shared -fPIC -fuse-cxa-atexit";

		if ( HasFlag ( "GCC32" ) )
			lib << " -m32";

		Point p = ExtractVersion();

		if ( !IsNull ( p.x ) && HasFlag ( "WIN32" ) )
		{
			lib << " -Xlinker --major-image-version -Xlinker " << p.x;

			if ( !IsNull ( p.y ) )
				lib << " -Xlinker --minor-image-version -Xlinker " << p.y;
		}

		lib << ' ' << link_options;

		lib << " -o ";
	}

	else
		lib = "ar -sr ";

	lib << GetPathQ ( product );

	String llib;

	for ( int i = 0; i < obj.GetCount(); i++ )
		llib << ' ' << GetPathQ ( obj[i] );

	PutConsole ( "Создаётся библиотека..." );

	DeleteFile ( hproduct );

	if ( is_shared )
	{
		for ( int i = 0; i < libpath.GetCount(); i++ )
			llib << " -L" << GetPathQ ( libpath[i] );

		for ( int i = 0; i < all_uses.GetCount(); i++ )
			llib << ' ' << GetPathQ ( GetSharedLibPath ( all_uses[i] ) );

		for ( int i = 0; i < all_libraries.GetCount(); i++ )
			llib << " -l" << GetPathQ ( all_libraries[i] );

		if ( HasFlag ( "POSIX" ) )
			llib << " -Wl,-soname," << GetSoname ( product );
	}

	String tmpFileName;

	if ( HasFlag ( "LINUX" ) || HasFlag ( "WIN32" ) )
	{
		if ( lib.GetCount() + llib.GetCount() >= 8192 )
		{
			tmpFileName = GetTempFileName();
			// можно просто поместить все данные одной строкой,
			// т.к. допустимый размер её около 130000 символов,
			// но мы разобьём её на несколько строк.
			FileOut f ( tmpFileName );

			while ( llib != "" )
			{
				int found = 0;
				bool quotes = false;
				int lim = min ( 8192, llib.GetCount() );

				for ( int i = 0; i < lim; i++ )
				{
					char c = llib[i];

					if ( isspace ( c ) && !quotes )
						found = i;
					else
						if ( c == '"' )
							quotes = !quotes;
				}

				if ( !found )
					found = llib.GetCount();

				// заменить все '\' на '/'`
				llib = UnixPath ( llib );

				f.PutLine ( llib.Left ( found ) );

				llib.Remove ( 0, found );
			}

			f.Close();

			lib << " @" << tmpFileName;
		}

		else
			lib << llib;
	}

	else
		lib << llib;

	int res = Execute ( lib );

	if ( tmpFileName.GetCount() )
		FileDelete ( tmpFileName );

	String folder, libF, soF, linkF;

	if ( HasFlag ( "POSIX" ) )
	{
		if ( is_shared )
		{
			folder = GetFileFolder ( hproduct );
			libF = GetFileName ( hproduct );
			soF = AppendFileName ( folder, GetSoname ( hproduct ) );
			linkF = AppendFileName ( folder, GetSoLinkName ( hproduct ) );
			//создать символьную ссылку на .so
			int r = symlink ( libF, soF );
			r = symlink ( libF, linkF );
			( void ) r;
		}
	}

	if ( res )
	{
		DeleteFile ( hproduct );

		if ( HasFlag ( "POSIX" ) )
		{
			if ( is_shared )
			{
				DeleteFile ( libF );
				DeleteFile ( linkF );
			}
		}

		return false;
	}

	PutConsole ( String().Cat() << hproduct << " (" << GetFileInfo ( hproduct ).length
				 << " Б) создано за " << GetPrintTime ( libtime ) );

	return true;
}

//Компонует
bool GccBuilder::Link ( const Vector<String>& linkfile, const String& linkoptions, bool createmap )
{
	if ( !Wait() )
		return false;

	PutLinking();

	if ( HasFlag ( "MAKE_MLIB" ) || HasFlag ( "MAKE_LIB" ) )
		return CreateLib ( ForceExt ( target, ".a" ), linkfile, Vector<String>(), Vector<String>(), linkoptions );

	int time = msecs();

#ifdef PLATFORM_OSX
	CocoaAppBundle();

#endif
	for ( int i = 0; i < linkfile.GetCount(); i++ )
		if ( GetFileTime ( linkfile[i] ) > targettime )
		{
			Vector<String> lib;
			String lnk = CompilerName();
//          if(IsVerbose())
//              lnk << " -v";

			if ( HasFlag ( "GCC32" ) )
				lnk << " -m32";

			if ( HasFlag ( "DLL" ) )
				lnk << " -shared -Wl,--out-implib=" << target << ".a";// -Wl,--export-all-symbols -Wl,--enable-auto-import";

			if ( !HasFlag ( "SHARED" ) && !HasFlag ( "SO" ) )
				lnk << " -static";

			if ( HasFlag ( "WINCE" ) )
				lnk << " -mwindowsce";
			else
				if ( HasFlag ( "WIN32" ) )
				{
					lnk << " -mthreads";

					if ( HasFlag ( "CLANG" ) )
					{
						if ( HasFlag ( "GUI" ) )
							lnk << " -mwindows";
						else
							lnk << " -mconsole";
					}

					else
					{
						lnk << " -mwindows";
						// if(HasFlag("MT"))

						if ( !HasFlag ( "GUI" ) )
							lnk << " -mconsole";
					}
				}

			lnk << " -o " << GetPathQ ( target );

			if ( createmap )
				lnk << " -Wl,-Map," << GetPathQ ( GetFileDirectory ( target ) + GetFileTitle ( target ) + ".map" );

			if ( HasFlag ( "DEBUG_MINIMAL" ) || HasFlag ( "DEBUG_FULL" ) )
				lnk << ( HasFlag ( "CLANG" ) && HasFlag ( "WIN32" ) ? " -Wl,-pdb=" : " -ggdb" );
			else
				lnk << ( !HasFlag ( "OSX" ) ? " -Wl,-s" : "" );

			for ( i = 0; i < libpath.GetCount(); i++ )
				lnk << " -L" << GetPathQ ( libpath[i] );

			MergeWith ( lnk, " ", linkoptions );

			String lfilename;

			if ( HasFlag ( "OBJC" ) )
			{
				String lfilename;
				String linklist;

				for ( i = 0; i < linkfile.GetCount(); i++ )
					if ( ToLower ( GetFileExt ( linkfile[i] ) ) == ".o" || ToLower ( GetFileExt ( linkfile[i] ) ) == ".a" )
						linklist << linkfile[i] << '\n';

				String linklistM = "Производится список компонуемых файлов ...\n";

				String odir = GetFileDirectory ( linkfile[0] );

				lfilename << GetFileFolder ( linkfile[0] ) << ".LinkFileList";

				linklistM  << lfilename;

				UPP::SaveFile ( lfilename, linklist );

				lnk << " -L" << GetPathQ ( odir )
				<< " -F" << GetPathQ ( odir )
				<< " -filelist " << lfilename << " ";

				PutConsole ( linklistM );
			}

			else
				for ( i = 0; i < linkfile.GetCount(); i++ )
				{
					if ( ToLower ( GetFileExt ( linkfile[i] ) ) == ".o" )
						lnk  << ' ' << GetPathQ ( linkfile[i] );
					else
						lib.Add ( linkfile[i] );
				}

			if ( !HasFlag ( "SOLARIS" ) && !HasFlag ( "OSX" ) && !HasFlag ( "OBJC" ) )
				lnk << " -Wl,--start-group ";

		for ( String s : pkg_config )
				lnk << " `pkg-config --libs " << s << "`";

			for ( int pass = 0; pass < 2; pass++ )
			{
				for ( i = 0; i < lib.GetCount(); i++ )
				{
					String ln = lib[i];
					String ext = ToLower ( GetFileExt ( ln ) );

					// unix shared libs shall have version number AFTER .so (sic)
					// so we shall find the true extension....

					if ( HasFlag ( "POSIX" ) && ext != ".so" )
					{
						const char *c = ln.Last();

						while ( --c >= ~ln )
							if ( !IsDigit ( *c ) && *c != '.' )
								break;

						int pos = int ( c - ~ln - 2 );

						if ( pos >= 0 && ToLower ( ln.Mid ( pos, 3 ) ) == ".so" )
							ext = ".so";
					}

					if ( pass == 0 )
					{
						if ( ext == ".a" )
							lnk << ' ' << GetPathQ ( FindInDirs ( libpath, lib[i] ) );
					}

					else
						if ( ext != ".a" )
						{
							if ( ext == ".so" || ext == ".dll" || ext == ".lib" )
								lnk << ' ' << GetPathQ ( FindInDirs ( libpath, lib[i] ) );
							else
								lnk << " -l" << ln;
						}
				}

				if ( pass == 1 && !HasFlag ( "SOLARIS" ) && !HasFlag ( "OSX" ) )
					lnk << " -Wl,--end-group";
			}

			PutConsole ( "Компоновка..." );

			bool error = false;
			CustomStep ( ".pre-link", Null, error );

			if ( !error && Execute ( lnk ) == 0 )
			{
				CustomStep ( ".post-link", Null, error );
				PutConsole ( String().Cat() << target << " (" << GetFileInfo ( target ).length
							 << " Б) скомпоновано за " << GetPrintTime ( time ) );
				return !error;
			}

			else
			{
				DeleteFile ( target );
				return false;
			}
		}

	PutConsole ( String().Cat() << target << " (" << GetFileInfo ( target ).length

				 << " Б) в свежем состоянии." );
	return true;
}

//Выполняет препроцессинг
bool GccBuilder::Preprocess ( const String& package, const String& file, const String& target, bool asmout )
{
	Package pkg;
	String packagePath = PackagePath ( package );
	pkg.Load ( packagePath );
	String packageDir = GetFileFolder ( packagePath );
	ChDir ( packageDir );
	PutVerbose ( "cd " + packageDir );

	String cmd = CmdLine ( package, pkg );
	cmd << " " << Gather ( pkg.option, config.GetKeys() );
	cmd << " -o " << target;
	cmd << ( asmout ? " -S " : " -E " ) << GetPathQ ( file );

	if ( BuilderUtils::IsCFile ( file ) )
		cmd << " " << c_options;
	else
		if ( BuilderUtils::IsCppFile ( file ) )
			cmd << " " << cpp_options;

	return Execute ( cmd );
}

//Создаёт сам построитель
Builder *CreateGccBuilder()
{
	return new GccBuilder;
}

//Регистрация построителей
INITIALIZER ( GccBuilder )
{
	RegisterBuilder ( "GCC", CreateGccBuilder );
	RegisterBuilder ( "CLANG", CreateGccBuilder );
}
